package com.ym.medical.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ym.common.constant.Constants;
import com.ym.common.constant.DictEnum;
import com.ym.common.enums.UserUserTypeEnum;
import com.ym.common.utils.StringUtil;
import com.ym.core.utils.tkmybatis.BaseSVImpl;
import com.ym.medical.dao.InformationDao;
import com.ym.medical.domain.entity.InformationEntity;
import com.ym.medical.domain.entity.InquiryOrderEntity;
import com.ym.medical.domain.entity.TopicEntity;
import com.ym.medical.domain.entity.UserEntity;
import com.ym.medical.domain.param.AddressListParam;
import com.ym.medical.domain.param.InformationParam;
import com.ym.medical.domain.vo.CounsellingRoomRecordVO;
import com.ym.medical.domain.vo.InformationVo;
import com.ym.medical.domain.vo.SimpleDoctorInfoVo;
import com.ym.medical.domain.vo.TopicAndPublisherInfoVo;
import com.ym.medical.enums.AddressGroupAlgIdentEnum;
import com.ym.medical.enums.InformationInforStateEnum;
import com.ym.medical.enums.InformationInforTypeEnum;
import com.ym.medical.enums.PlaformSourceEnum;
import com.ym.medical.enums.UserBadRecordUpTypeEnum;
import com.ym.medical.service.ICommonSV;
import com.ym.medical.service.IDoctorDetailsSV;
import com.ym.medical.service.IInformationSV;
import com.ym.medical.service.IInquiryOrderSV;
import com.ym.medical.service.ISysDictSV;
import com.ym.medical.service.IUserSV;
import com.ym.medical.service.IWxTemplateMsgSV;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 平台公告、医生接单后回复了你的消息、退款成功通知、医生发布的新话题Service业务层处理
 *
 * @author ym
 * @date 2020-08-21
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class InformationSVImpl extends BaseSVImpl<InformationEntity, InformationDao> implements IInformationSV {


	private static final Logger LOGGER = LoggerFactory.getLogger(InformationSVImpl.class);
	@Autowired
	private IUserSV userSV;

	@Autowired
	@Lazy
	private IInquiryOrderSV inquiryOrderSV;

	@Autowired
	private IDoctorDetailsSV doctorDetailsSV;

	@Autowired
	private ICommonSV commonSV;

	@Autowired
	private ISysDictSV sysDictSV;

	@Autowired
	private IWxTemplateMsgSV wxTemplateMsgSV;

	/**
	 * 保存消息
	 *
	 * @param infoType        消息类别  (InformationInforTypeEnum)
	 * @param sendObj         发送对象id
	 * @param receiverObj     接收对象id
	 * @param infoTitle       消息标题
	 * @param infoContent     消息内容
	 * @param infoUrl         消息url
	 * @param infoDestination 消息目的地
	 * @param extObj          消息扩展内容
	 */
	private void saveInformation(String infoType, Long sendObj, Long receiverObj, String infoTitle, String infoContent, String infoUrl, String infoDestination, Object extObj) {
		InformationEntity information = new InformationEntity();
		information.setInforType(infoType);
		information.setInforState(InformationInforStateEnum.NO_READ.getKey());
		information.setSendObjId(sendObj);
		information.setReceiverObjId(receiverObj);
		information.setInforTitle(infoTitle);
		information.setInforData(infoContent);
		information.setSrcUrl(infoUrl);
		information.setDestination(infoDestination);
		//消息扩展字段(object对象)
		information.setExtContent(JSONObject.toJSONString(extObj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat));
		InformationEntity informationModel = new InformationEntity();
		BeanUtils.copyProperties(information, informationModel);
		List<InformationEntity> informationList = this.selectList(informationModel);
		LOGGER.info("保存问诊消息 {}", information);
		if (informationList.isEmpty()) {
			this.insert(information);
		}
	}


	/**
	 * 话题消息
	 *
	 * @param topic
	 * @param addressLists 接受对象
	 */
	@Override
	public void generateTopicInformation(TopicEntity topic, List<AddressListParam> addressLists) {
		Long publisher = topic.getPublisher();        //医生
		Long sendObj = topic.getPublisher();        //患者
		String title = topic.getTopicTitle();        //话题标题
		String content = topic.getTopicContent();    //内容
		String url = topic.getTopicFileId();        //附件主键

		List<SimpleDoctorInfoVo> simpleDoctorInfo = doctorDetailsSV.selectSimpleDoctorInfo(publisher);        //查询医生的个人信息
		if (addressLists != null && !addressLists.isEmpty()) {
			for (AddressListParam addressList : addressLists) {
				Long toUser = addressList.getUserId();
				String userType = addressList.getAlgIdent();
				String destination = null;
				//目的地 (患者 医生)
				if ((userType.equals(AddressGroupAlgIdentEnum.IN_PATIENTS_WITH.getKey()))) {
					destination = UserUserTypeEnum.PATIENT.getKey();
				} else {
					destination = UserUserTypeEnum.DOCTOR.getKey();
				}

				//查询医生的姓名
				String realName = userSV.selectById(topic.getPublisher()).getRealName();

				TopicAndPublisherInfoVo topicAndPublisherInfo = new TopicAndPublisherInfoVo();
				topicAndPublisherInfo.setTopic(topic);
				topicAndPublisherInfo.setPublisherInfo(simpleDoctorInfo.get(0));

				//保存消息
				saveInformation(InformationInforTypeEnum.TOPIC.getKey(), sendObj, toUser, title, content, url, destination, topicAndPublisherInfo);

				//发送模板消息
				String page = Constants.MiniPage.MINI_TOPIC_PAGE + "?id=" + topic.getId();
				wxTemplateMsgSV.sendTopicMsg(PlaformSourceEnum.SMALL_PROGRAM, toUser, page,
						StringUtil.strformat(title, 20), StringUtil.strformat(realName, 20), realName + "医生发布了一篇话题，快来看看吧~~~");
			}
		}
	}

	/**
	 * 支付消息
	 *
	 * @param sendObj
	 * @param receiver
	 * @param title
	 * @param content
	 * @param destination
	 * @param extObj
	 * @param extIoNum
	 * @param paymentPrice
	 * @param tdTime
	 */
	@Override
	public void generatePayInformation(Long sendObj, Long receiver, String title, String content, String infoUrl, String destination, Object extObj, String extIoNum, BigDecimal paymentPrice, Date tdTime, PlaformSourceEnum plaformSourceEnum) {
		//保存消息
		saveInformation(InformationInforTypeEnum.PAY.getKey(), sendObj, receiver, title, content, infoUrl, destination, extObj);

		//发送模板消息
		wxTemplateMsgSV.sendPayMsg(plaformSourceEnum, receiver,
				extIoNum, paymentPrice + "元", DateUtil.date(tdTime).toString());
	}

	/**
	 * 退费消息
	 *
	 * @param order 订单id
	 * @param payee 收款方id
	 */

	@Override
	public void generateRefordInformation(InquiryOrderEntity order, Long payee) {
		PlaformSourceEnum plaformSourceEnum = DictEnum.valueOfEnum(PlaformSourceEnum.class, order.getPaySource());  //发送人登录方式
		//根据收款人id查询对应的信息
		UserEntity doctor = userSV.selectById(payee);
		String realName = doctor.getRealName();
		Long sendObj = doctor.getId();
		Long receiver = order.getUserId();
		//todo 此处取ioTypeName
		String title = realName + "医生" + order.getIoType() + "费";
		String content = order.getIllnessDesc();
		String destination = UserUserTypeEnum.PATIENT.getKey();
		//保存消息
		saveInformation(InformationInforTypeEnum.REFUND.getKey(), sendObj, receiver, title, content, null, destination, order);

		//发送模板消息
		// todo 此处取getOrderSourceName
		wxTemplateMsgSV.sendRefundMsg(plaformSourceEnum, receiver,
				order.getIoNum(), StringUtil.strformat(order.getOrderSource(), 20), order.getPaymentPrice() + "元", DateUtil.date(order.getPaymentTime()).toString());
	}

	@Override
	public void generatePhoneInquiryInformation(Long sendObj, Long receiverObj, String title, String content, String infoUrl, Long orderId) {
		//查询问诊消息
		CounsellingRoomRecordVO counsellingRoomRecordVO = inquiryOrderSV.selectOrderDesc(orderId);
		String destination = UserUserTypeEnum.PATIENT.getKey();
		//保存消息
		saveInformation(InformationInforTypeEnum.INQUIRY.getKey(), sendObj, receiverObj, title, content, infoUrl, destination, counsellingRoomRecordVO);

		//发送模板消息
		Long userId = counsellingRoomRecordVO.getUserId();
		PlaformSourceEnum plaformSourceEnum = DictEnum.valueOfEnum(PlaformSourceEnum.class, counsellingRoomRecordVO.getPaySource());  //支付来源
		String page = Constants.MiniPage.MINI_PHONE_PAGE + "?id=" + orderId;
		String patientName = counsellingRoomRecordVO.getPatientName();
		String appOintTime = counsellingRoomRecordVO.getAppointTime().toString();
		String doctorName = counsellingRoomRecordVO.getDoctorName();
		String doctorType = StringUtil.strformat(counsellingRoomRecordVO.getDoctorType(), 20);
		String hosName = StringUtil.strformat(counsellingRoomRecordVO.getHosName(), 20);

		//发送模板消息
		wxTemplateMsgSV.sendPhoneInquiryMsg(plaformSourceEnum, userId, page, patientName, appOintTime, doctorName, doctorType, hosName);
	}

	@Override
	public void generateInquiryInformation(Long orderId, String title) {
		CounsellingRoomRecordVO counsellingRoomRecordVO = inquiryOrderSV.selectOrderDesc(orderId);        //查询问诊消息
		String destination = UserUserTypeEnum.PATIENT.getKey();                            //目的地
		String doctorName = counsellingRoomRecordVO.getDoctorName();                                    //医生姓名
		//保存消息
		saveInformation(InformationInforTypeEnum.INQUIRY.getKey(), counsellingRoomRecordVO.getDoctorId(), counsellingRoomRecordVO.getUserId(), doctorName + " " + title, counsellingRoomRecordVO.getContent(), counsellingRoomRecordVO.getAttach(), destination, counsellingRoomRecordVO);
		//发送模到哪个页面
		String page = Constants.MiniPage.MINI_INQUIRY_PAGE + "?type=2&yunId=" + counsellingRoomRecordVO.getPatientAccid() + "&counsellingRoomId=" + counsellingRoomRecordVO.getRoomMainId()
				+ "&orderId=" + counsellingRoomRecordVO.getId() + "&chatMaxNum=" + counsellingRoomRecordVO.getChatMaxNum() + "&roomState=" + counsellingRoomRecordVO.getRoomState()
				+ "&orderSource=" + counsellingRoomRecordVO.getOrderSource() + "&doctorName=" + counsellingRoomRecordVO.getDoctorName() + "&jumpChat=1";
		if (Constants.InquiryAdvice.ANSWER.equals(title)) {
			sendReplyTemplateData(counsellingRoomRecordVO, page);
		} else if (Constants.InquiryAdvice.EVALUATE.equals(title)) {
			sendEvaluateTemplateData(counsellingRoomRecordVO, page);
		} else if (Constants.InquiryAdvice.SUMMARY.equals(title)) {
			sendsummaryTemplateData(counsellingRoomRecordVO, page);
		}
	}

	@Override
	public List<InformationVo> countNoReadInformation(InformationParam informationModel) {
		return mapper.countGroupByInformation(informationModel);
	}

	/**
	 * 医生总结模板消息
	 *
	 * @param counsellingRoomRecordVO
	 * @param page
	 */
	private void sendsummaryTemplateData(CounsellingRoomRecordVO counsellingRoomRecordVO, String page) {
		PlaformSourceEnum plaformSourceEnum = DictEnum.valueOfEnum(PlaformSourceEnum.class, counsellingRoomRecordVO.getPaySource());  //支付来源
		//发送模板消息
		wxTemplateMsgSV.sendSummaryMsg(plaformSourceEnum, counsellingRoomRecordVO.getUserId(), page,
				counsellingRoomRecordVO.getDoctorName(),
				StringUtil.strformat(counsellingRoomRecordVO.getContent(), 20),
				StringUtil.strformat("可能的疾病: " + counsellingRoomRecordVO.getPossDisease() + "; 诊断时间: " + counsellingRoomRecordVO.getSummaryTime(), 20),
				"你可以查看详情对该医生进行评价");
	}

	/**
	 * 医生接单答复模板消息
	 *
	 * @param counsellingRoomRecordVO
	 * @param page
	 */
	private void sendReplyTemplateData(CounsellingRoomRecordVO counsellingRoomRecordVO, String page) {
		//发送模板消息
		wxTemplateMsgSV.sendReplyMsg(DictEnum.valueOfEnum(PlaformSourceEnum.class, counsellingRoomRecordVO.getPaySource()), counsellingRoomRecordVO.getUserId(), page,
				counsellingRoomRecordVO.getDoctorName(),
				StringUtil.strformat(counsellingRoomRecordVO.getContent(), 20),
				"医生正在查看你的病情", "您可以点击查看详情直接回复医生");
	}


	/**
	 * 就诊评价提醒模板消息
	 *
	 * @param counsellingRoomRecordVO
	 * @param page
	 */
	private void sendEvaluateTemplateData(CounsellingRoomRecordVO counsellingRoomRecordVO, String page) {
		PlaformSourceEnum plaformSourceEnum = DictEnum.valueOfEnum(PlaformSourceEnum.class, counsellingRoomRecordVO.getPaySource());

		//发送模板消息
		wxTemplateMsgSV.sendEvaluateMsg(plaformSourceEnum, counsellingRoomRecordVO.getUserId(), page,
				counsellingRoomRecordVO.getDoctorName(), StringUtil.strformat(counsellingRoomRecordVO.getContent(), 20),
				StringUtil.strformat("患者信息: " + counsellingRoomRecordVO.getPatientName() + "-" + counsellingRoomRecordVO.getPatientAge(), 20),
				"欢迎您来对本次服务进行评价");
	}


	@Override
	public List<InformationVo> informationUnread(Long id) {
		String sql = "SELECT " +
				"a.*, " +
				"b.num inforCount " +
				"from information a " +
				"LEFT JOIN ( " +
				"select     " +
				" infor_type, " +
				" receiver_obj_id,    " +
				" count(id) num     " +
				" from information  where  infor_State = '01'   " +
				" group by infor_type,receiver_obj_id     " +
				") b on b.infor_type = a.infor_type and b.receiver_obj_id = a.receiver_obj_id " +
				"INNER JOIN ( " +
				" SELECT " +
				" max(a.id) id, " +
				"  receiver_obj_id,  " +
				"  infor_type " +
				" from information a  group by infor_type,receiver_obj_id " +
				") c on c.id = a.id and c.receiver_obj_id = a.receiver_obj_id " +
				" where 1 = 1 and a.receiver_obj_id = #{params.id} and destination = '02'    ";
		Map<String, Object> params = new HashMap<>();
		params.put("id", id);
		List<InformationVo> jsonObjects = commonSV.queryListEntity(sql, params, InformationVo.class);
		return jsonObjects;
	}

	@Override
	public Map<String, Object> listPageInformation(InformationParam informationModel, int pageNum, int pageSize) {
		Map<String, Object> result = new HashMap<>();
		List<InformationEntity> informationList = listInformation(informationModel);
		int resultSize = informationList.size();
		int totalPage = resultSize / pageSize;
		int pageNo = (pageNum - 1) * pageSize;
		int nextPage = 0;
		boolean hasNextPage = false;
		boolean isLastPage = true;
		if (pageNo + pageSize > resultSize) {
			informationList = informationList.subList(pageNo, resultSize);
		} else {
			informationList = informationList.subList(pageNo, pageNo + pageSize);
			nextPage = pageNum + 1;
			if (nextPage > totalPage) {
				nextPage = totalPage;
			}
			hasNextPage = true;
			isLastPage = false;
		}
		result.put("nextPage", nextPage);
		result.put("hasNextPage", hasNextPage);
		result.put("isLastPage", isLastPage);
		result.put("pageNum", pageNum);
		result.put("list", informationList);
		return result;
	}

	/**
	 * 问诊消息 帖子消息 去重集合
	 *
	 * @param informationModel
	 * @return
	 */
	public List<InformationEntity> listInformation(InformationParam informationModel) {
		List<InformationEntity> informationList = this.selectList(informationModel.covert());
		for (int i = 0; i < informationList.size() - 1; i++) {
			for (int j = informationList.size() - 1; j > i; j--) {
				InformationInforTypeEnum enumByCode =DictEnum.valueOfEnum(InformationInforTypeEnum.class,informationList.get(i).getInforType());
				switch (enumByCode) {
					case INQUIRY:
						//展示最新的问诊消息
						CounsellingRoomRecordVO counsellingRoomRecord = JSONObject.parseObject(informationList.get(i).getExtContent(), CounsellingRoomRecordVO.class);
						CounsellingRoomRecordVO roomRecord = JSONObject.parseObject(informationList.get(j).getExtContent(), CounsellingRoomRecordVO.class);
						if (counsellingRoomRecord != null && roomRecord != null && counsellingRoomRecord.getId().equals(roomRecord.getId())) {
							//修改问诊消息状态为已读
							InformationEntity readInformation = informationList.get(j);
							readInformation.setInforState(InformationInforStateEnum.OVER_READ.getKey());
							this.updateById(readInformation);
							informationList.remove(informationList.get(j));
						}
						continue;
					case TOPIC:
						//帖子消息去重
						TopicEntity topic = JSONObject.parseObject(informationList.get(i).getExtContent(), TopicEntity.class);
						TopicEntity exitTopic = JSONObject.parseObject(informationList.get(i).getExtContent(), TopicEntity.class);
						if (topic != null && exitTopic != null && topic.getId().equals(exitTopic.getId())) {
							//修改帖子消息状态为已读
							InformationEntity readInformation = informationList.get(j);
							readInformation.setInforState(InformationInforStateEnum.OVER_READ.getKey());
							this.updateById(readInformation);
							informationList.remove(informationList.get(j));
						}
						continue;
					default:
						continue;
				}
			}
		}
		return informationList;
	}

	@Override
	public void generateOrderException(InquiryOrderEntity order, Long doctorId, String upType, String remark) {
		CounsellingRoomRecordVO counsellingRoomRecordVO = inquiryOrderSV.selectOrderDesc(order.getId());
		String dictValue = sysDictSV.getDictValue(UserBadRecordUpTypeEnum.class, upType);
		String content = String.format("订单号: %s 被认为是包含\"%s\",请您及时处理查看！", order
				.getIoNum(), dictValue);

		//保存消息
		saveInformation(InformationInforTypeEnum.INQUIRY.getKey(), doctorId, order.getUserId(), "您的问诊订单存在一些问题，请注意查看！", content, null, UserUserTypeEnum.PATIENT.getKey(), counsellingRoomRecordVO);

		//发送模板消息
		String page = Constants.MiniPage.MINI_INQUIRY_PAGE + "?type=2&yunId=" + counsellingRoomRecordVO.getDoctorAccid() + "&counsellingRoomId=" + counsellingRoomRecordVO.getRoomMainId()
				+ "&orderId=" + counsellingRoomRecordVO.getId() + "&chatMaxNum=" + counsellingRoomRecordVO.getChatMaxNum() + "&roomState=" + counsellingRoomRecordVO.getRoomState()
				+ "&orderSource=" + counsellingRoomRecordVO.getOrderSource() + "&doctorName=" + counsellingRoomRecordVO.getDoctorName() + "&jumpChat=1";
		PlaformSourceEnum plaformSourceEnum = DictEnum.valueOfEnum(PlaformSourceEnum.class,order.getPaySource());
		wxTemplateMsgSV.sendOrderException(plaformSourceEnum, order.getId(), page,
				counsellingRoomRecordVO.getDoctorName(), counsellingRoomRecordVO.getAppointTime().toString(),
				StringUtil.strformat(content, 20), "点击详情更换医生问诊");

	}

	/**
	 * 随访消息列表
	 *
	 * @param pageNo
	 * @param pageNum
	 * @param model
	 * @return
	 */
	@Override
	public PageInfo<InformationEntity> infoMessage(int pageNo, int pageNum, InformationParam model) {
		PageHelper.startPage(pageNo, pageNum);
		model.setInforType(InformationInforTypeEnum.FOLLOW_UP.getKey());
		List<InformationEntity> infor = this.selectList(model.covert());
		return new PageInfo<>(infor);
	}
}
